﻿using DrawTools.Serialize;
using System;
using System.Windows;
using System.Windows.Media;

namespace DrawTools.Tools
{
    /// <summary>
    /// 角度
    /// </summary>
    [SerializerType(typeof(DrawAngleSerializer))]
    public sealed class AngleDrawTool : DrawGeometryBase
    {
        #region 字段/属性

        private Point? vertex, startPoint, mousePoint;      // 顶点、开始描点、鼠标移动点
        private Point[] points;                             // 角度连线
        private Point arcPoint1, arcPoint2;                 // 圆弧起始点
        private Point arcTextPoint1, arcTextPoint2, textCenterPoint, textPoint;     // 文字圆弧起始点，及中点
        private double? k1, k2, k3;                     // 两直线斜率，及文字斜率
        private double angle, angle1, angle2, arcLen;   // 两直线夹角， 及圆弧半径，
        private double textAngle, arcTextLen;           // 文字夹角，文字圆弧半径
        private double minWidth;
        private FormattedText formattedText;

        protected override Point BeginingPoint => base.BeginingPoint.X != 0 ? base.BeginingPoint : this.vertex!.Value;

        #endregion 字段

        public AngleDrawTool(DrawingCanvas drawingCanvas) : base(drawingCanvas)
        {
            DrawingToolType = DrawToolType.Angle;

            // 准备要处理的事件
            CanTouchDown = true;
        }

        protected override void OnDrawing(DrawingContext dc)
        {
            base.OnDrawing(dc);
            if (!string.IsNullOrEmpty(Text))
            {
                if (formattedText == null) formattedText = GetFormattedText();
                var textGeometry = formattedText.BuildGeometry(this.textPoint);
                var transformGroup = new TransformGroup();
                transformGroup.Children.Add(new RotateTransform(textAngle, textCenterPoint.X, textCenterPoint.Y));
                transformGroup.Children.Add(geometry.Transform);
                textGeometry.Transform = transformGroup;
                dc.DrawGeometry(Pen.Brush, null, textGeometry);
            }
        }

        #region 鼠标键盘事件

        public override bool OnTouchLeave(Point point, bool isLeaved = false)
        {
            if (formattedText == null) drawingCanvas.DeleteVisual(this);
            else//角度文本
            {
                Draw();
            }
            drawingCanvas.DeleteWorkingDrawTool(this);
            IsFinish = true;
            CanTouchDown = false;
            CanTouchMove = false;
            CanTouchLeave = false;

            if (TouchId == 0 && drawingCanvas.IsMouseCaptured) drawingCanvas.ReleaseMouseCapture();
            return true;
        }

        public override bool OnTouchDown(int touchId, Point point)
        {
            TouchId = touchId;

            if (!vertex.HasValue)
            {
                drawingCanvas.AddWorkingDrawTool(this);

                minWidth = Pen.Thickness * 20;
                arcLen = Pen.Thickness * 15;
                arcTextLen = Pen.Thickness * 25;

                vertex = point;

                geometry = new PathGeometry();

                var figure = new PathFigure { StartPoint = point };
                pathGeometry.Figures.Add(figure);

                CanTouchMove = true;

                if (TouchId != 0 || !drawingCanvas.CaptureMouse())
                    CanTouchLeave = true;

                drawingCanvas.AddVisual(this);
            }
            else if ((point - vertex.Value).Length > minWidth && !startPoint.HasValue)
            {
                startPoint = point;

                var figure = pathGeometry.Figures[0];
                figure.StartPoint = point;

                points = new Point[2];
                points[0] = vertex.Value;

                var line = new LineSegment(vertex.Value, IsStroked) { IsSmoothJoin = true };

                if (mousePoint.HasValue)
                {
                    figure.Segments[figure.Segments.Count - 1] = line;
                    mousePoint = null;
                }
                else
                    figure.Segments.Add(line);

                var dc = RenderOpen();
                dc.DrawGeometry(null, Pen, geometry);
                dc.Close();

                if (point.X == vertex.Value.X)
                {
                    arcPoint1.X = arcTextPoint1.X = point.X;
                    arcPoint1.Y = vertex.Value.Y + (point.Y > vertex.Value.Y ? arcLen : -arcLen);
                    arcTextPoint1.Y = vertex.Value.Y + (point.Y > vertex.Value.Y ? arcTextLen : -arcTextLen);
                }
                else
                {
                    k1 = (point.Y - vertex.Value.Y) / (point.X - vertex.Value.X);

                    var offsetX = Math.Sqrt(arcLen * arcLen / (k1.Value * k1.Value + 1)) * (point.X > vertex.Value.X ? 1 : -1);

                    arcPoint1.X = vertex.Value.X + offsetX;
                    arcPoint1.Y = vertex.Value.Y + offsetX * k1.Value;

                    offsetX = Math.Sqrt(arcTextLen * arcTextLen / (k1.Value * k1.Value + 1)) * (point.X > vertex.Value.X ? 1 : -1);

                    arcTextPoint1.X = vertex.Value.X + offsetX;
                    arcTextPoint1.Y = vertex.Value.Y + offsetX * k1.Value;
                }

                figure = new PathFigure { StartPoint = arcPoint1 };
                pathGeometry.Figures.Add(figure);

                figure = new PathFigure { StartPoint = vertex.Value };
                pathGeometry.Figures.Add(figure);
            }
            else
                return OnTouchLeave(point);

            return true;
        }

        public override bool OnTouchMove(Point point)
        {
            if (!startPoint.HasValue)
            {
                // 画线
                var dc = RenderOpen();

                if ((point - vertex.Value).Length < minWidth)
                {
                    dc.Close();
                    return true;
                }

                var figure = pathGeometry.Figures[0];
                var line = new LineSegment(point, IsStroked) { IsSmoothJoin = true };

                if (mousePoint.HasValue)
                    figure.Segments[figure.Segments.Count - 1] = line;
                else
                    figure.Segments.Add(line);

                mousePoint = point;

                dc.DrawGeometry(null, Pen, geometry);
                dc.Close();
            }
            else
            {
                // 画夹角
                if ((point - vertex.Value).Length < minWidth)
                    return true;

                mousePoint = points[1] = point;

                var polyLine = new PolyLineSegment(points, true);

                var figure = pathGeometry.Figures[0];
                figure.Segments[figure.Segments.Count - 1] = polyLine;

                // 画圆弧
                if (point.X == vertex.Value.X)
                {
                    arcPoint2.X = arcTextPoint2.X = point.X;
                    arcPoint2.Y = vertex.Value.Y + (point.Y > vertex.Value.Y ? arcLen : -arcLen);
                    arcTextPoint2.Y = vertex.Value.Y + (point.Y > vertex.Value.Y ? arcTextLen : -arcTextLen);
                }
                else
                {
                    k2 = (point.Y - vertex.Value.Y) / (point.X - vertex.Value.X);

                    var offsetX = Math.Sqrt(arcLen * arcLen / (k2.Value * k2.Value + 1)) * (point.X > vertex.Value.X ? 1 : -1);

                    arcPoint2.X = vertex.Value.X + offsetX;
                    arcPoint2.Y = vertex.Value.Y + offsetX * k2.Value;

                    offsetX = Math.Sqrt(arcTextLen * arcTextLen / (k2.Value * k2.Value + 1)) * (point.X > vertex.Value.X ? 1 : -1);

                    arcTextPoint2.X = vertex.Value.X + offsetX;
                    arcTextPoint2.Y = vertex.Value.Y + offsetX * k2.Value;
                }

                if (k1.HasValue)
                {
                    angle1 = Math.Atan(k1.Value) / Math.PI * 180;

                    if (arcPoint1.X < vertex.Value.X)
                        angle1 += 180;
                    else if (k1.Value < 0)
                        angle1 += 360;
                }
                else
                    angle1 = arcPoint1.Y > vertex.Value.Y ? 90 : -90;

                if (k2.HasValue)
                {
                    angle2 = Math.Atan(k2.Value) / Math.PI * 180;

                    if (arcPoint2.X < vertex.Value.X)
                        angle2 += 180;
                    else if (k2.Value < 0)
                        angle2 += 360;
                }
                else
                    angle2 = arcPoint2.Y > vertex.Value.Y ? 90 : -90;

                angle = (angle2 + 360 - angle1) % 360;
                var clockwise = angle < 180;
                var arc = new ArcSegment(arcPoint2, new Size(arcLen, arcLen), 0, false, clockwise ? SweepDirection.Clockwise : SweepDirection.Counterclockwise, true);

                figure = pathGeometry.Figures[1];

                if (figure.Segments.Count == 0) figure.Segments.Add(arc);
                else figure.Segments[0] = arc;

                var dc = RenderOpen();

                // 画文字
                angle %= 180;

                if (!clockwise) angle = 180 - angle;

                Text = angle.ToString("0.00") + "°";

                formattedText = GetFormattedText();

                textCenterPoint.X = (arcTextPoint1.X + arcTextPoint2.X) / 2;
                textCenterPoint.Y = (arcTextPoint1.Y + arcTextPoint2.Y) / 2;

                if (textCenterPoint.X == vertex.Value.X)
                {
                    if (textCenterPoint.Y >= vertex.Value.Y)
                    {
                        textAngle = 90;
                        textCenterPoint.Y = vertex.Value.Y + arcTextLen;
                    }
                    else
                    {
                        textAngle = -90;
                        textCenterPoint.Y = vertex.Value.Y - arcTextLen;
                    }
                }
                else
                {
                    k3 = (textCenterPoint.Y - vertex.Value.Y) / (textCenterPoint.X - vertex.Value.X);

                    textAngle = Math.Atan(k3.Value) / Math.PI * 180;

                    var offsetX = Math.Sqrt(arcTextLen * arcTextLen / (k3.Value * k3.Value + 1)) * (textCenterPoint.X > vertex.Value.X ? 1 : -1);

                    textCenterPoint.X = vertex.Value.X + offsetX;
                    textCenterPoint.Y = vertex.Value.Y + offsetX * k3.Value;
                }

                figure = pathGeometry.Figures[2];
                var line = new LineSegment(textCenterPoint, IsStroked);

                if (figure.Segments.Count == 0) figure.Segments.Add(line);
                else figure.Segments[0] = line;

                dc.DrawGeometry(null, Pen, geometry);

                dc.PushTransform(new RotateTransform(textAngle, textCenterPoint.X, textCenterPoint.Y));

                var _textAngle = textAngle;

                textPoint.X = textCenterPoint.X;
                textPoint.Y = textCenterPoint.Y - FontSize / 2;

                if (textPoint.X < vertex.Value.X) _textAngle += 180;
                else if (k3.Value < 0) _textAngle += 360;

                if (_textAngle >= 90 && _textAngle <= 270)
                {
                    var width = Text.Length * FontSize / 2 + FontSize;
                    textPoint.X -= width;
                }
                else
                    textPoint.X += FontSize / 2;

                dc.DrawText(formattedText, textPoint);
                dc.Pop();

                dc.Close();
            }

            return true;
        }

        #endregion 鼠标键盘事件


    }
}